from typing import Dict, Any, Sequence

from mcp import Tool
from mcp.types import TextContent

from config.dbconfig import get_db_config_by_name
from databases.database_factory import DatabaseOperationFactory
from tools.base import ToolsBase


class SqlCreator(ToolsBase):
    """专业的 SQL 语句生成工具类
    
    该工具是生成任何可执行 SQL 语句（包括查询、插入、更新、删除、DDL、配置查询等）的唯一推荐方式。
    当用户提出任何涉及数据库操作的需求时，必须优先调用此工具生成正确的 SQL 语句。
    禁止模型自行编写 SQL，因为语法准确性、字段名、表名等细节必须由该工具根据数据库元数据生成。
    此工具输出的 SQL 可用于后续执行。
    """
    
    # 工具名称
    name = "sql_creator"
    # 工具描述，包含中英文说明和使用规范
    description = ("专业的 SQL 语句生成工具。该工具是生成任何可执行 SQL 语句（包括查询、插入、更新、删除、DDL、配置查询等）的唯一推荐方式。"
                   "当用户提出任何涉及数据库操作的需求时，必须优先调用此工具生成正确的 SQL 语句。"
                   "禁止模型自行编写 SQL，因为语法准确性、字段名、表名等细节必须由该工具根据数据库元数据生成。"
                   "此工具输出的 SQL 可用于后续执行。"
                   "A professional SQL statement generation tool. This tool is the only recommended way to generate any executable SQL statements "
                   "(including queries, inserts, updates, deletes, DDL, configuration queries, etc.). When users request any database-related "
                   "operations, this tool must be prioritized to generate the correct SQL statements. The model is prohibited "
                   "from writing SQL on its own, as syntax accuracy, field names, table names, and other details must be generated by "
                   "the tool based on database metadata. The SQL output from this tool can be used for subsequent execution."

                   )

    def get_tool_description(self) -> Tool:
        """获取工具的详细描述信息
        
        返回一个Tool对象，包含工具名称、描述和输入参数模式。
        该描述用于MCP服务识别和调用工具。
        
        Returns:
            Tool: 包含工具描述信息的对象
        """
        return Tool(
            name=self.name,
            description=self.description,
            inputSchema={
                "type": "object",
                "properties": {
                    "text": {
                        "type": "string",
                        "description": "用户需求"
                    },
                    "pool_name": {
                        "type": "string",
                        "description": "线程池名称,若没有指定默认是default"
                    },
                    "database": {
                        "type": "string",
                        "description": "数据库名称,若无指定默认为default"
                    },
                    "schema": {
                        "type": "string",
                        "description": "数据库模式名称,若无指定默认为default"
                    }
                },
                "required": ["text"]
            }
        )

    async def run_tool(self, arguments: Dict[str, Any]) -> Sequence[TextContent]:
        """执行SQL生成工具
        
        根据传入的参数生成SQL语句，基于数据库元数据确保语法正确性。
        
        Args:
            arguments: 包含执行参数的字典
                - text (str): 用户的数据库操作需求
                - pool_name (str, optional): 数据库连接池名称，默认为"default"
                - database (str, optional): 数据库名称，默认为"default"
                - schema (str, optional): 数据库模式名称，默认为"default"

        Returns:
            Sequence[TextContent]: 包含生成的SQL语句和相关说明的文本内容序列
        """
        # 检查参数中是否包含必需的text字段
        if "text" not in arguments:
            return [TextContent(type="text", text="错误: 缺少需要执行的操作内容")]

        # 获取用户需求
        text = arguments["text"]

        # 获取连接池名称，默认为"default"
        pool_name = arguments.get("pool_name", "default")

        # 获取数据库名称，默认为"default"
        database = arguments.get("database", "default")

        # 获取数据库模式名称，默认为"default"
        schema = arguments.get("schema", "default")

        # 获取数据库配置
        db_config = get_db_config_by_name(pool_name)

        # 如果数据库名称为"default"，则使用配置中的数据库名
        if database == "default":
            database = db_config.get("database")
        # 如果模式名称为"default"，则使用配置中的模式名（如果存在）
        if schema == "default":
            schema = db_config.get("schema", None)

        # 获取数据库版本号
        factory = DatabaseOperationFactory.get_factory_by_pool_name(pool_name)
        db_version = factory.create_db_version().get_db_version(pool_name)

        # 构建结果文本，包含角色定义、核心原则、工具能力、执行流程等信息
        results = f"""
        # 角色
        你是一位资深数据库专家，精通主流数据库（MySQL、Oracle、SQL Server、PostgreSQL 等）的语法与元数据管理。你具备跨语言语义理解能力，
        能准确解析用户以**中文或英文**提出的数据库操作请求，通过工具调用获取真实数据库结构信息，并基于真实元数据生成可执行 SQL。
        
        # 核心原则
        在生成任何可执行 SQL 语句前，你必须：
        1. **绝不翻译或转换用户输入中的实体名称**（如表名、字段名、连接池名、数据库名）。保持原始拼写和大小写。
        2. **绝不假设或构造**表名、字段名、模式名或配置项。
        3. **必须通过工具调用**获取真实元数据，包括：数据库版本、表名、字段结构、索引等。
        4. 所有 SQL 必须基于真实元数据生成，语法兼容目标数据库类型与版本。
        5. 所有 SQL 必须显式包含数据库名、模式名（如适用）、表名，确保可执行性。
        6. 输出格式应尊重用户请求（如要求 Markdown，则用 Markdown 输出 SQL 或结果）。
        
        
        # 工具能力（你可调用的工具）
        - `get_db_version()`: 获取当前连接的数据库类型与版本号。
        - `get_table_name(关键词)`: 根据关键词（中文或英文）搜索数据库中匹配的真实表名。**输入必须是用户原始关键词**。。
        - `get_table_desc(表名列表)`: 获取指定表的字段名、列注释等结构信息。
        - `get_table_index(表名列表)`: 获取指定表的索引信息。
        
        # 执行流程（必须严格遵守）
        对于任何数据库操作请求，执行以下步骤：
        1. **解析用户意图**：识别操作类型（查询、插入、更新、删除等）和目标对象（表、字段、条件等）。
        2. **提取原始关键词**：从用户请求中提取表名相关关键词（如 "user info table"、"订单表"），**保持原样，不翻译、不改写**。
        3. **调用 `get_table_name(原始关键词)`**：获取数据库中真实存在的表名（如 "user_info"）。
        4. **调用 `get_table_desc([真实表名])`**：获取字段名、类型、主键等，用于构建 SQL。
        5. **生成 SQL**：
            - 基于真实元数据 + 数据库类型与版本，生成完整、可执行的 SQL
            - 使用真实表名、字段名。
            - 遵循数据库命名规范：
            - MySQL / Oracle: `数据库名.表名`
            - SQL Server / PostgreSQL: `数据库名.模式名.表名`（模式名默认 `public` 或 `dbo`，除非元数据指定）
        6. **按用户要求格式输出**：如要求 Markdown，则用 Markdown 代码块包裹 SQL 或结果。

        # 语言处理规则
        - 用户使用英文提问 → 保持英文关键词，不转中文。
        - 用户使用中文提问 → 保持中文关键词，用于 `get_table_name` 调用。
        - **禁止语义翻译**：例如：
          - ❌ 不要把 "user info table" 转为 "用户信息表"
          - ✅ 直接用 "user info table" 调用 `get_table_name("user info table")`
        
        
        #本次任务信息
        - 数据库类型与版本号:
        {db_config["type"]}
        {db_version}
        
        - 所需连接的数据库名：
        {database}
            
      """
        # 如果模式名存在，则添加到结果文本中
        if schema is not None:
            results += f"- 数据库模式：{schema}\n"

        # 继续构建结果文本，包含SQL操作内容和示例
        results += f"""
        - SQL操作内容（增删改查、数据库配置查询语句、操作语句等）:
        {text}
        
        # 示例 1（中文输入）
        用户问：“查询用户信息表的数据”
        你应执行：
        1. 调用 `get_table_name("用户信息表")` → 返回 `user_info`
        2. 调用 `get_table_desc(["user_info"])` → 获取字段：`user_id, name, phone, create_time`
        3. 确认数据库类型版本，若无提供调用 →`get_db_version()` 返回 `MySQL 8.0`
        4. 生成 SQL：`SELECT user_id, name, phone, create_time FROM mydb.user_info;`
        
        
        # 示例 2（英文输入）
        用户：“The connection pool is pg. Query data from the user info table. Output in markdown.”
        执行流程：
        1. 提取关键词：`user info table`（保持原样）
        2. 调用 `get_table_name("user info table")` → 返回 `user_info`
        3. 调用 `get_table_desc(["user_info"])` → 获取字段：`id, name, email`
        4. 确认数据库类型版本，若无提供调用 `get_db_version("pg")` → 返回 `PostgreSQL 14`
        5. 生成 SQL：`SELECT id, name, email FROM mydb.public.user_info;`
        6. 输出（Markdown）：
           ```markdown
           ```sql
           SELECT id, name, email FROM mydb.public.user_info;
        
        
        # 特别强调
        - 禁止输出如 `SELECT * FROM 用户信息表` 或 `SELECT * FROM user_info`（未验证表名/字段）。
        - 禁止构造不存在的字段或表名。
        - 所有操作必须基于工具返回的真实元数据。
        - 所有工具调用的参数必须来自用户原始输入或工具返回结果。
        - 禁止引入任何"中间翻译"或"语义映射"。
        - 输出 SQL 必须可执行、语法正确、对象名完整。
        - 不要重复调用该工具
        
        # 任务
        请根据上述流程，处理用户请求，确保输出的 SQL 是基于真实元数据、可执行、语法正确的语句。
        
        """


        # 返回结果文本内容
        return [TextContent(type="text", text="".join(results))]